﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using OpenRasta.Web;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.web;
using uREST.Core.Attributes;
using uREST.Core.Handlers;
using uREST.CMS.Extensions;

namespace uREST.CMS.Handlers
{
    [UmbracoAuthorize(Applications = "content")]
    public class DocumentHandler : AbstractHandler
    {
        public DocumentHandler(ICommunicationContext context)
            : base(context)
        { }

        // GET (LIST)
        [HttpOperation(ForUriName = "DocumentList")]
        public OperationResult GetDocumentList(
            [Optional, DefaultParameterValue(-1)] int parentId,
            [Optional] string docTypeAlias)
        {
            var documentList = new List<Document>();

            if (parentId <= 0)
                parentId = Math.Max(-1, AuthenticatedUser.StartNodeId);

            if (parentId > 0)
            {
                Document parentDoc = null;

                try
                {
                    parentDoc = new Document(parentId);
                }
                catch { }

                if (parentDoc == null)
                    return new OperationResult.BadRequest();

                if (!AuthenticatedUser.CanAccess(parentDoc))
                    return new OperationResult.Forbidden();

                try
                {
                    if (parentDoc.HasChildren)
                        documentList.AddRange(parentDoc.Children);
                }
                catch
                { }
            }
            else
            {
                documentList.AddRange(Document.GetRootDocuments());
            }

            if (!string.IsNullOrEmpty(docTypeAlias))
                documentList = documentList.Where(doc => doc.ContentType.Alias == docTypeAlias).ToList();

            return new OperationResult.OK { ResponseResource = documentList.ToResourceList() };
        }

        // GET (SINGLE)
        [HttpOperation(ForUriName = "Document")]
        public OperationResult GetDocument(
            int id)
        {
            Document doc = null;

            try
            {
                doc = new Document(id);
            }
            catch
            { }

            if (doc == null)
                return new OperationResult.NotFound();

            if (!AuthenticatedUser.CanAccess(doc))
                return new OperationResult.Forbidden();

            return new OperationResult.OK { ResponseResource = doc.ToResource() };
        }

        // CREATE
        [HttpOperation(ForUriName = "DocumentList")]
        public OperationResult PostDocument(
            [Optional, DefaultParameterValue(-1)] int parentId,
            Resources.Document resource)
        {
            if (resource.Id > 0 || string.IsNullOrEmpty(resource.DocTypeAlias) || string.IsNullOrEmpty(resource.Name))
                return new OperationResult.BadRequest();

            var docType = DocumentType.GetByAlias(resource.DocTypeAlias);
            if (docType == null)
                return new OperationResult.BadRequest();

            parentId = parentId == -1 && resource.ParentId > 0 ?
                resource.ParentId :
                parentId == -1 ? Math.Max(-1, AuthenticatedUser.StartNodeId) : parentId;

            Document parentDocument = null;

            try
            {
                parentDocument = new Document(parentId);
            }
            catch
            { }

            if (parentDocument == null)
                return new OperationResult.NotFound();

            if (!AuthenticatedUser.CanAccess(parentDocument))
                return new OperationResult.Forbidden();

            var doc = Document.MakeNew(resource.Name, docType, AuthenticatedUser, parentId);
            doc.ReleaseDate = resource.ReleaseDate;
            doc.ExpireDate = resource.ExpireDate;

            if (resource.Properties != null && resource.Properties.Count > 0)
            {
                foreach (var propResource in resource.Properties)
                {
                    var prop = doc.getProperty(propResource.Key);
                    if (prop != null)
                        prop.Value = propResource.Value;
                }
            }

            HandlePublish(doc, resource.PublishAction, AuthenticatedUser);

            return new OperationResult.Created { ResponseResource = doc.ToResource() };
        }

        // UPDATE
        [HttpOperation(ForUriName = "Document")]
        public OperationResult PutDocument(int id, 
            Resources.Document resource)
        {
            Document doc = null;

            try
            {
                doc = new Document(id);
            }
            catch
            { }

            if (doc == null)
                return new OperationResult.NotFound();

            doc.ReleaseDate = resource.ReleaseDate;
            doc.ExpireDate = resource.ExpireDate;

            if (resource.ParentId > 0)
            {
                Document parentDocument = null;

                try
                {
                    parentDocument = new Document(resource.ParentId);
                }
                catch
                { }

                if (parentDocument == null)
                    return new OperationResult.NotFound();

                if (!AuthenticatedUser.CanAccess(parentDocument))
                    return new OperationResult.Forbidden();

                doc.Move(resource.ParentId);
            }

            if (!string.IsNullOrEmpty(resource.Name))
                doc.Text = resource.Name;

            if (resource.Properties != null && resource.Properties.Count > 0)
            {
                foreach (var propResource in resource.Properties)
                {
                    var prop = doc.getProperty(propResource.Key);
                    if (prop != null)
                        prop.Value = propResource.Value;
                }
            }

            HandlePublish(doc, resource.PublishAction, AuthenticatedUser);

            return new OperationResult.Created { ResponseResource = doc.ToResource() };
        }

        // DELETE
        [HttpOperation(ForUriName = "Document")]
        public OperationResult DeleteDocument(
            int id,
            [Optional, DefaultParameterValue(false)] bool permanent)
        {
            Document doc = null;

            try
            {
                doc = new Document(id);
            }
            catch
            { }

            if (doc == null)
                return new OperationResult.NotFound();

            if (!AuthenticatedUser.CanAccess(doc))
                return new OperationResult.Forbidden();

            try
            {
                doc.delete(permanent);
                return new OperationResult.NoContent();
            }
            catch
            {
                return new OperationResult.InternalServerError();
            }
        }

        protected void HandlePublish(Document doc, Resources.PublishAction publishAction, User user)
        {
            switch (publishAction)
            {
                case Resources.PublishAction.Publish:
                    doc.Publish(user);
                    umbraco.library.UpdateDocumentCache(doc.Id);
                    break;
                case Resources.PublishAction.UnPublish:
                    doc.Publish(user);
                    umbraco.library.UnPublishSingleNode(doc.Id);
                    break;
                case Resources.PublishAction.Ignore:
                    if (doc.Published)
                    {
                        doc.Publish(user);
                        umbraco.library.UpdateDocumentCache(doc.Id);
                    }
                    else
                    {
                        doc.Publish(user);
                        umbraco.library.UnPublishSingleNode(doc.Id);
                    }
                    break;
            }

        }
    }
}
